#include "peer_connection_wrapper.hpp"
#include "p2pms_log.hpp"

namespace p2pms
{

////////////////////////////////////////////////////////////////////////////////////////////////////
// --- CreateSessionDescriptionObserver Implementation ---

PeerConnectionWrapper::CreateSessionDescriptionObserver::CreateSessionDescriptionObserver(
	rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc) : m_pc(pc)
{

}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
std::future<std::string> PeerConnectionWrapper::CreateSessionDescriptionObserver::GetCreateFuture()
{
	return m_create_promise.get_future();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::CreateSessionDescriptionObserver::OnSuccess(
	webrtc::SessionDescriptionInterface* desc)
{
	LOG_INF("SDP Create Success: type={}", SdpTypeToString(desc->GetType()));

	std::string sdp;
	desc->ToString(&sdp);

	auto observer = rtc::make_ref_counted<SetSessionDescriptionObserver>();
	m_pc->SetLocalDescription(observer.get(), desc);
	
	try {
		observer.get();
		m_create_promise.set_value(sdp);
	} 
	catch (const std::exception& e) {
		m_create_promise.set_exception(
			std::make_exception_ptr(std::runtime_error("Set description failed")));
	}
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::CreateSessionDescriptionObserver::OnFailure(webrtc::RTCError error)
{
	LOG_ERR("SDP Observer Failure: message={}", error.message());

	m_create_promise.set_exception(
		std::make_exception_ptr(std::runtime_error(error.message())));
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// --- SetSessionDescriptionObserver Implementation ---

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
std::future<void> PeerConnectionWrapper::SetSessionDescriptionObserver::GetSetFuture()
{
	return m_set_promise.get_future();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::SetSessionDescriptionObserver::OnSuccess()
{
	m_set_promise.set_value();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::SetSessionDescriptionObserver::OnFailure(webrtc::RTCError error)
{
	m_set_promise.set_exception(
		std::make_exception_ptr(std::runtime_error(error.message())));
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// --- PeerConnectionWrapper Implementation ---

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
PeerConnectionWrapper::PeerConnectionWrapper(rtc::Thread* sdk_thread,
											 std::shared_ptr<IPeerConnectionHandler> handler)
	: m_sdk_thread(sdk_thread), m_handler(handler)
{
	RTC_DCHECK(m_sdk_thread);
	RTC_DCHECK(handler);
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
PeerConnectionWrapper::~PeerConnectionWrapper()
{
	LOG_INF("PeerConnectionWrapper::~PeerConnectionWrapper()");

	Destroy();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool PeerConnectionWrapper::Init(webrtc::PeerConnectionFactoryInterface* pc_factory)
{
	RTC_DCHECK(!m_pc); // 确保只初始化一次
	RTC_DCHECK(pc_factory);

	webrtc::PeerConnectionInterface::RTCConfiguration config;
	config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;

	// 添加基本的 ICE 配置
	webrtc::PeerConnectionInterface::IceServer server;
	server.uri = "stun:stun.l.google.com:19302";
	config.servers.push_back(server);

	webrtc::PeerConnectionDependencies pc_deps(this);
	auto pc_or_error = pc_factory->CreatePeerConnectionOrError(config, std::move(pc_deps));

	if (!pc_or_error.ok()) {
		LOG_ERR("Failed to create PeerConnection: {}", pc_or_error.error().message());
		return false;
	}

	m_pc = pc_or_error.MoveValue();
	return m_pc != nullptr;
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::Destroy()
{
	LOG_INF("Destroying PeerConnectionWrapper");

	if (m_pc) {
		m_handler.reset();
		m_pc->Close();
		m_pc = nullptr;
	}
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
std::future<std::string> PeerConnectionWrapper::CreateOffer()
{
	auto observer = rtc::make_ref_counted<CreateSessionDescriptionObserver>(m_pc);
	m_pc->CreateOffer(observer.get(), webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
	return observer->GetCreateFuture();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
std::future<std::string> PeerConnectionWrapper::CreateAnswer()
{
	auto observer = rtc::make_ref_counted<CreateSessionDescriptionObserver>(m_pc);
	m_pc->CreateAnswer(observer.get(), webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
	return observer->GetCreateFuture();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
std::future<void> 
PeerConnectionWrapper::SetRemoteDescription(webrtc::SessionDescriptionInterface* desc)
{
	auto observer = rtc::make_ref_counted<SetSessionDescriptionObserver>();
	m_pc->SetRemoteDescription(observer.get(), desc);
	return observer->GetSetFuture();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::AddIceCandidate(std::unique_ptr<webrtc::IceCandidateInterface> candidate)
{
	if (!m_pc->AddIceCandidate(candidate.release())) {
		LOG_ERR("Failed to add ICE candidate");
	}
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>> 
PeerConnectionWrapper::AddTransceiver(cricket::MediaType media_type, 
	const webrtc::RtpTransceiverInit& init)
{
	return m_pc->AddTransceiver(media_type, init);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// --- PeerConnectionObserver ---

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::OnSignalingChange(
	webrtc::PeerConnectionInterface::SignalingState new_state)
{
	LOG_DBG("Signaling state changed: {}", webrtc::PeerConnectionInterface::AsString(new_state));

	m_sdk_thread->PostTask([handler_wptr = m_handler, new_state]() {
		if (auto handler_sptr = handler_wptr.lock()) {
			handler_sptr->OnSignalingChange(new_state);
		}
	});
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::OnRenegotiationNeeded()
{
	LOG_DBG("Renegotiation needed");

	m_sdk_thread->PostTask([handler_wptr = m_handler]() {
		if (auto handler_sptr = handler_wptr.lock()) {
			handler_sptr->OnRenegotiationNeeded();
		}
	});
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::OnIceConnectionChange(
	webrtc::PeerConnectionInterface::IceConnectionState new_state)
{
	LOG_DBG("ICE connection state changed: {}", webrtc::PeerConnectionInterface::AsString(new_state));

	m_sdk_thread->PostTask([handler_wptr = m_handler, new_state]() {
		if (auto handler_sptr = handler_wptr.lock()) {
			handler_sptr->OnIceConnectionChange(new_state);
		}
	});
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::OnIceGatheringChange(
	webrtc::PeerConnectionInterface::IceGatheringState new_state)
{
	LOG_DBG("ICE gathering state changed: {}", webrtc::PeerConnectionInterface::AsString(new_state));

	m_sdk_thread->PostTask([handler_wptr = m_handler, new_state]() {
		if (auto handler_sptr = handler_wptr.lock()) {
			handler_sptr->OnIceGatheringChange(new_state);
		}
	});
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::OnIceCandidate(const webrtc::IceCandidateInterface* candidate)
{
	LOG_DBG("New ICE candidate: sdp_mid={}, sdp_mline_index={}, candidate={}",
		candidate->sdp_mid(), candidate->sdp_mline_index(), candidate->candidate().ToString());

	// 1. 在回调线程从 candidate 指针中提取数据。
	std::string sdp;
	if (!candidate->ToString(&sdp)) {
		LOG_ERR("Failed to serialize ICE candidate to string.");
		return;
	}
	std::string sdp_mid = candidate->sdp_mid();
	int sdp_mline_index = candidate->sdp_mline_index();

	// 2. 将提取出的数据（而不是指针）通过 PostTask 传递给 SDK 线程。
	m_sdk_thread->PostTask([handler_wptr = m_handler, sdp, sdp_mid, sdp_mline_index]() {
		// 3. 在 SDK 线程中，使用数据重新创建一个新的 candidate 对象。
		webrtc::SdpParseError error;
		std::unique_ptr<webrtc::IceCandidateInterface> new_candidate(
			webrtc::CreateIceCandidate(sdp_mid, sdp_mline_index, sdp, &error));

		if (!new_candidate) {
			LOG_ERR("Failed to re-create ICE candidate from data: {}", error.description);
			return;
		}

		// 4. 将新创建的、所有权清晰的 candidate 传递给 handler。
		//    unique_ptr 会确保在 lambda 作用域结束后，对象被正确销毁。
		if (auto handler_sptr = handler_wptr.lock()) {
			handler_sptr->OnIceCandidate(new_candidate.get());
		}
	});
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::OnAddTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver, 
	const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& streams)
{
	LOG_DBG("Track added: receiver_id={}, streams_count={}", receiver->id(), streams.size());

	m_sdk_thread->PostTask([handler_wptr = m_handler, receiver, streams]() {
		if (auto handler_sptr = handler_wptr.lock()) {
			handler_sptr->OnAddTrack(receiver, streams);
		}
	});
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void PeerConnectionWrapper::OnRemoveTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver)
{
	LOG_DBG("Track removed: receiver_id={}", receiver->id());

	m_sdk_thread->PostTask([handler_wptr = m_handler, receiver]() {
		if (auto handler_sptr = handler_wptr.lock()) {
			handler_sptr->OnRemoveTrack(receiver);
		}
	});
}

} // namespace p2pms